package com.edushare.common.dao;

import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import org.apache.cayenne.DataObjectUtils;
import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.query.Ordering;
import org.apache.cayenne.query.QueryCacheStrategy;
import org.apache.cayenne.query.SelectQuery;
import org.apache.cayenne.query.SortOrder;

import com.edushare.common.backup.SystemBackupUtils;
import com.edushare.common.constants.ConfigPropertyName;
import com.edushare.common.orm.ORMInterface;
import com.edushare.common.util.SystemUtils;
import com.edushare.common.vo.ConfigProperties;
import com.edushare.common.vo.SystemBackup;

public class SystemBackupDAO extends CayenneBasedDAO {

	public SystemBackupDAO(ORMInterface ormInterface) {
		super(ormInterface);
	}
	
	/** creates backup directory and registers the object to DB */
	public void createBackup(SystemBackup bkp){
		bkp.setDirectoryPath(SystemBackupUtils.createNewBackupDirectory());
		bkp.setCreationTimestamp(new Date());
		getDataContext().registerNewObject(bkp);
	}

	public SystemBackup getSystemBackupById(int id) {
		return DataObjectUtils.objectForPK(getDataContext(), SystemBackup.class, id);
	}

	/**
	 * 
	 * @return the first SystemBackup object that has status other than FAILED or COMPLETED
	 */
	public SystemBackup getCurrentlyRunningBackup() {
		Expression exp = Expression.fromString("backupStatus != $failed and backupStatus != $completed");
		HashMap<String, Integer> hm = new HashMap<String, Integer>();
		hm.put("failed", ConfigProperties.SYSTEM_BACKUP_STATUS_FAILED);
		hm.put("completed", ConfigProperties.SYSTEM_BACKUP_STATUS_OK);
		SelectQuery query = new SelectQuery(SystemBackup.class, exp.expWithParameters(hm));
		query.setCacheStrategy(QueryCacheStrategy.NO_CACHE);
		List<SystemBackup> lbkp = getDataContext().performQuery(query);
		if(lbkp!=null && lbkp.size()>0)
			return lbkp.get(0); //idea it maximum one backup running at a time
		return null;
	}

	/**
	 * Sets all the currently running or half-ran backup processes to failed status.
	 * Also, resets the global configuration lock (ConfigPropertyName.SYSTEM_BACKUP_STATUS) to FAILED state.
	 * Note: this method commits the data-context as well.
	 */
	public void flushAnyRunningBackupProcess() {
		ConfigProperties conf = new ConfigPropertiesDAO(ormInterface).getConfigProperty(ConfigPropertyName.SYSTEM_BACKUP_STATUS, false);
		if(Integer.parseInt(conf.getValue()) != ConfigProperties.SYSTEM_BACKUP_STATUS_FAILED &&
				Integer.parseInt(conf.getValue()) != ConfigProperties.SYSTEM_BACKUP_STATUS_OK){
			conf.setValue(""+ConfigProperties.SYSTEM_BACKUP_STATUS_FAILED);
		}
		
		Expression exp = Expression.fromString("backupStatus != $failed and backupStatus != $completed");
		HashMap<String, Integer> hm = new HashMap<String, Integer>();
		hm.put("failed", ConfigProperties.SYSTEM_BACKUP_STATUS_FAILED);
		hm.put("completed", ConfigProperties.SYSTEM_BACKUP_STATUS_OK);
		SelectQuery query = new SelectQuery(SystemBackup.class, exp.expWithParameters(hm));
		query.setCacheStrategy(QueryCacheStrategy.NO_CACHE);
		List<SystemBackup> lbkp = getDataContext().performQuery(query);
		for(SystemBackup bkp: lbkp){
			bkp.setBackupStatus(ConfigProperties.SYSTEM_BACKUP_STATUS_FAILED);
		}
		
		getDataContext().commitChanges();
	}

	public SystemBackup getLatestBackup(int systemBackupStatus) {
		
		Expression exp = Expression.fromString("backupStatus = $completed");
		HashMap<String, Integer> hm = new HashMap<String, Integer>();
		hm.put("completed", ConfigProperties.SYSTEM_BACKUP_STATUS_OK);
		SelectQuery query = new SelectQuery(SystemBackup.class, exp.expWithParameters(hm));
		query.addOrdering("creationTimestamp", SortOrder.DESCENDING);
		List<SystemBackup> lbkp = getDataContext().performQuery(query);
		if(lbkp!=null && lbkp.size()>0)
			return lbkp.get(0); //get the latest backup, if any
		return null;
	}

	public List<SystemBackup> getAllBackups() {
		SelectQuery query = new SelectQuery(SystemBackup.class);
		query.addOrdering("creationTimestamp", SortOrder.DESCENDING);
		return getDataContext().performQuery(query);
	}

	/**
	 * Deletes backup object and all the files that are stored for this backup on the server
	 * @param SystemBackupObject
	 */
	public void delete(SystemBackup bkp) {
		File dir = new File(SystemUtils.getAbsolutePathFromRelative(bkp.getDirectoryPath()));
		if(dir.exists()){
			if(dir.isDirectory()){
				//Assuming no sub directory inside, delete files
				for(File f:dir.listFiles()){
					f.delete();
				}
				//now dir empty delete dir
				dir.delete();
			}
		}
		getDataContext().deleteObject(bkp);
	}

}
